package com.bolang.onlycode.demo.juc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 首先需要获得锁，目的是确保数组修改的可见性和排他性。
 * 当数组数量等于数组长度时，表示数组已满，则调用notFull.await()
 * 当前线程随之释放锁并进入等待状态
 * 如果数组数量不等于数组长度，表示数组未满，则添加元素到数组中，
 * 同时通知等待在notEmpty上的线程，数组中已经有新元素可以获取
 *
 * @param <T>
 */
public class BoundedQuene<T> {
    private Object[] itemsArr;
    // 添加的下标，删除的下标和数组当前数量
    private int addIndex,removeIndex,count;
    private Lock lock = new ReentrantLock();
    private Condition  notEmpty =lock.newCondition();
    private Condition  notFull =lock.newCondition();
    public BoundedQuene(int size){
        itemsArr = new Object[size];
    }
    // 添加一个元素，如果数组满，则添加线程进入等待状态，直到有"空位"
    public void add(T t)throws InterruptedException{
          lock.lock();
          try{
              while (count==itemsArr.length){
                  notFull.await();
              }
              itemsArr[addIndex]=t;
              if(++addIndex ==itemsArr.length){
                    addIndex=0;
              }
              ++count;
              notEmpty.signal();
          }finally {
              lock.unlock();
          }
    }
    // 由头部删除一个元素，如果数组空，则删除线程进入等待状态，直到有新添加元素
    public T remove() throws InterruptedException{
        lock.lock();
        try{
            while(count==0){
                notEmpty.await();
            }
            Object x =itemsArr[removeIndex];
            if(++removeIndex == itemsArr.length){
                 removeIndex =0;
            }
            --count;
            notFull.signal();
            return (T)x;
        }finally {
            lock.unlock();
        }
    }

}
